gsk: Add GskShadowNode
authorBenjamin Otte <otte@redhat.com>
Sun, 18 Dec 2016 23:45:35 +0000 (00:45 +0100)
committerBenjamin Otte <otte@redhat.com>
Tue, 20 Dec 2016 17:01:12 +0000 (18:01 +0100)
... and make the icon rendering code use it.

This requires moving even more shadow renering code into GSK, but so be
it. At least the "shadows not implemented" warning is now gone!

16 files changed:
docs/reference/gsk/gsk4-sections.txt
gsk/gskcairoblur.c
gsk/gskcairoblurprivate.h
gsk/gskenums.h
gsk/gskrendernode.h
gsk/gskrendernodeimpl.c
gsk/gskrendernodeprivate.h
gtk/gtkcssshadowsvalue.c
gtk/gtkcssshadowsvalueprivate.h
gtk/gtkcssshadowvalue.c
gtk/gtkcssshadowvalueprivate.h
gtk/gtkrendericon.c
gtk/gtksnapshot.c
gtk/gtksnapshot.h
gtk/inspector/gtktreemodelrendernode.c
gtk/inspector/recorder.c

index 023abe5d562588c47a86d7e1347a017c5e19afc3..20785e7ff7ff332119274b33b734bce7984e595e 100644 (file)
@@ -50,6 +50,8 @@ gsk_clip_node_new
 gsk_clip_node_get_child
 gsk_rounded_clip_node_new
 gsk_rounded_clip_node_get_child
+GskShadow
+gsk_shadow_node_new
 GskBlendMode
 gsk_blend_node_new
 gsk_cross_fade_node_new
index 0fcd1c63b4a32d9fca3e886981ff5eaf2edc77ca..0e66a5eb020f743cca088cf4d454d7e0b9734480 100644 (file)
@@ -280,3 +280,121 @@ gsk_cairo_blur_compute_pixels (double radius)
   return floor (radius * GAUSSIAN_SCALE_FACTOR * 1.5 + 0.5);
 }
 
+static gboolean
+needs_blur (float radius)
+{
+  /* The code doesn't actually do any blurring for radius 1, as it
+   * ends up with box filter size 1 */
+  if (radius <= 1.0)
+    return FALSE;
+
+  return TRUE;
+}
+
+static const cairo_user_data_key_t original_cr_key;
+
+cairo_t *
+gsk_cairo_blur_start_drawing (cairo_t         *cr,
+                              float            radius,
+                              GskBlurFlags     blur_flags)
+{
+  cairo_rectangle_int_t clip_rect;
+  cairo_surface_t *surface;
+  cairo_t *blur_cr;
+  gdouble clip_radius;
+  gdouble x_scale, y_scale;
+  gboolean blur_x = (blur_flags & GSK_BLUR_X) != 0;
+  gboolean blur_y = (blur_flags & GSK_BLUR_Y) != 0;
+
+  if (!needs_blur (radius))
+    return cr;
+
+  gdk_cairo_get_clip_rectangle (cr, &clip_rect);
+
+  clip_radius = gsk_cairo_blur_compute_pixels (radius);
+
+  x_scale = y_scale = 1;
+  cairo_surface_get_device_scale (cairo_get_target (cr), &x_scale, &y_scale);
+
+  if (blur_flags & GSK_BLUR_REPEAT)
+    {
+      if (!blur_x)
+        clip_rect.width = 1;
+      if (!blur_y)
+        clip_rect.height = 1;
+    }
+
+  /* Create a larger surface to center the blur. */
+  surface = cairo_surface_create_similar_image (cairo_get_target (cr),
+                                                CAIRO_FORMAT_A8,
+                                                x_scale * (clip_rect.width + (blur_x ? 2 * clip_radius : 0)),
+                                                y_scale * (clip_rect.height + (blur_y ? 2 * clip_radius : 0)));
+  cairo_surface_set_device_scale (surface, x_scale, y_scale);
+  cairo_surface_set_device_offset (surface,
+                                    x_scale * ((blur_x ? clip_radius : 0) - clip_rect.x),
+                                    y_scale * ((blur_y ? clip_radius * y_scale : 0) - clip_rect.y));
+
+  blur_cr = cairo_create (surface);
+  cairo_set_user_data (blur_cr, &original_cr_key, cairo_reference (cr), (cairo_destroy_func_t) cairo_destroy);
+
+  if (cairo_has_current_point (cr))
+    {
+      double x, y;
+
+      cairo_get_current_point (cr, &x, &y);
+      cairo_move_to (blur_cr, x, y);
+    }
+
+  return blur_cr;
+}
+
+static void
+mask_surface_repeat (cairo_t         *cr,
+                     cairo_surface_t *surface)
+{
+  cairo_pattern_t *pattern;
+
+  pattern = cairo_pattern_create_for_surface (surface);
+  cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+
+  cairo_mask (cr, pattern);
+
+  cairo_pattern_destroy (pattern);
+}
+
+cairo_t *
+gsk_cairo_blur_finish_drawing (cairo_t         *cr,
+                               float            radius,
+                               const GdkRGBA   *color,
+                               GskBlurFlags     blur_flags)
+{
+  cairo_t *original_cr;
+  cairo_surface_t *surface;
+  gdouble x_scale;
+
+  if (!needs_blur (radius))
+    return cr;
+
+  original_cr = cairo_get_user_data (cr, &original_cr_key);
+
+  /* Blur the surface. */
+  surface = cairo_get_target (cr);
+
+  x_scale = 1;
+  cairo_surface_get_device_scale (cairo_get_target (cr), &x_scale, NULL);
+
+  gsk_cairo_blur_surface (surface, x_scale * radius, blur_flags);
+
+  gdk_cairo_set_source_rgba (original_cr, color);
+  if (blur_flags & GSK_BLUR_REPEAT)
+    mask_surface_repeat (original_cr, surface);
+  else
+    cairo_mask_surface (original_cr, surface, 0, 0);
+
+  cairo_destroy (cr);
+
+  cairo_surface_destroy (surface);
+
+  return original_cr;
+}
+
index d723ca6f96390f5963e6ba61a897945d6e9c3850..cd1e68758aac0ef80a22b5d0a34bd009ac7089ac 100644 (file)
@@ -24,7 +24,7 @@
 #ifndef _GSK_CAIRO_BLUR_H
 #define _GSK_CAIRO_BLUR_H
 
-#include <glib.h>
+#include <gdk/gdk.h>
 #include <cairo.h>
 
 G_BEGIN_DECLS
@@ -41,6 +41,14 @@ void            gsk_cairo_blur_surface          (cairo_surface_t *surface,
                                                 GskBlurFlags     flags);
 int             gsk_cairo_blur_compute_pixels   (double           radius);
 
+cairo_t *       gsk_cairo_blur_start_drawing    (cairo_t         *cr,
+                                                 float            radius,
+                                                 GskBlurFlags     blur_flags);
+cairo_t *       gsk_cairo_blur_finish_drawing   (cairo_t         *cr,
+                                                 float            radius,
+                                                 const GdkRGBA   *color,
+                                                 GskBlurFlags     blur_flags);
+
 G_END_DECLS
 
 #endif /* _GSK_CAIRO_BLUR_H */
index 7bad39d1c29774314633dd170828445648078d8e..9defa366537863cd3b017e400f921a8a0e36be31 100644 (file)
@@ -38,6 +38,7 @@
  * @GSK_OPACITY_NODE: A node that changes the opacity of its child
  * @GSK_CLIP_NODE: A node that clips its child to a rectangular area
  * @GSK_ROUNDED_CLIP_NODE: A node that clips its child to a rounded rectangle
+ * @GSK_SHADOW_NODE: A node that draws a shadow below its child
  * @GSK_BLEND_NODE: A node the blends two children together
  * @GSK_CROSS_FADE_NODE: A node the cross-fades between two children
  *
@@ -58,6 +59,7 @@ typedef enum {
   GSK_OPACITY_NODE,
   GSK_CLIP_NODE,
   GSK_ROUNDED_CLIP_NODE,
+  GSK_SHADOW_NODE,
   GSK_BLEND_NODE,
   GSK_CROSS_FADE_NODE
 } GskRenderNodeType;
index a349b8b302a17c0003d910d260c3ea7d5d32ffd8..1c4620737b01aae8c7ce19de74e33a1568695863 100644 (file)
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
 
 typedef struct _GskRenderNode           GskRenderNode;
 typedef struct _GskColorStop            GskColorStop;
+typedef struct _GskShadow               GskShadow;
 
 struct _GskColorStop
 {
@@ -41,6 +42,15 @@ struct _GskColorStop
   GdkRGBA color;
 };
 
+struct _GskShadow
+{
+  GdkRGBA color;
+  float dx;
+  float dy;
+  float spread;
+  float radius;
+};
+
 GDK_AVAILABLE_IN_3_90
 GType gsk_render_node_get_type (void) G_GNUC_CONST;
 
@@ -117,6 +127,11 @@ GskRenderNode *         gsk_rounded_clip_node_new               (GskRenderNode
 GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_rounded_clip_node_get_child         (GskRenderNode            *node);
 
+GDK_AVAILABLE_IN_3_90
+GskRenderNode *         gsk_shadow_node_new                     (GskRenderNode            *child,
+                                                                 const GskShadow          *shadows,
+                                                                 gsize                     n_shadows);
+
 GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_blend_node_new                      (GskRenderNode            *bottom,
                                                                  GskRenderNode            *top,
index c5d8d615d3a06191f8c00e552bf782b3316b76ab..a7453c6e8804c9aadd917f70b8abe792808299ee 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "gskrendernodeprivate.h"
 
+#include "gskcairoblurprivate.h"
 #include "gskdebugprivate.h"
 #include "gskrendererprivate.h"
 #include "gskroundedrectprivate.h"
@@ -1410,6 +1411,175 @@ gsk_rounded_clip_node_peek_clip (GskRenderNode *node)
   return &self->clip;
 }
 
+/*** GSK_SHADOW_NODE ***/
+
+typedef struct _GskShadowNode GskShadowNode;
+
+struct _GskShadowNode
+{
+  GskRenderNode render_node;
+
+  GskRenderNode *child;
+
+  GskShadow *shadows;
+  gsize n_shadows;
+};
+
+static void
+gsk_shadow_node_finalize (GskRenderNode *node)
+{
+  GskShadowNode *self = (GskShadowNode *) node;
+
+  gsk_render_node_unref (self->child);
+
+  g_free (self->shadows);
+}
+
+static void
+gsk_shadow_node_make_immutable (GskRenderNode *node)
+{
+  GskShadowNode *self = (GskShadowNode *) node;
+
+  gsk_render_node_make_immutable (self->child);
+}
+
+static void
+gsk_shadow_node_draw (GskRenderNode *node,
+                      cairo_t       *cr)
+{
+  GskShadowNode *self = (GskShadowNode *) node;
+  cairo_pattern_t *pattern;
+  gsize i;
+
+  cairo_push_group (cr);
+  gsk_render_node_draw (self->child, cr);
+  pattern = cairo_pop_group (cr);
+
+  for (i = 0; i < self->n_shadows; i++)
+    {
+      GskShadow *shadow = &self->shadows[i];
+
+      /* We don't need to draw invisible shadows */
+      if (gdk_rgba_is_clear (&shadow->color))
+        continue;
+
+      cairo_save (cr);
+      gdk_cairo_set_source_rgba (cr, &shadow->color);
+      cr = gsk_cairo_blur_start_drawing (cr, shadow->radius, GSK_BLUR_X | GSK_BLUR_Y);
+
+      cairo_translate (cr, shadow->dx, shadow->dy);
+      cairo_mask (cr, pattern);
+
+      cr = gsk_cairo_blur_finish_drawing (cr, shadow->radius, &shadow->color, GSK_BLUR_X | GSK_BLUR_Y);
+      cairo_restore (cr);
+    }
+
+  cairo_set_source (cr, pattern);
+  cairo_paint (cr);
+
+  cairo_pattern_destroy (pattern);
+}
+
+static void
+gsk_shadow_node_get_bounds (GskRenderNode   *node,
+                            graphene_rect_t *bounds)
+{
+  GskShadowNode *self = (GskShadowNode *) node;
+  float top = 0, right = 0, bottom = 0, left = 0;
+  gsize i;
+
+  gsk_render_node_get_bounds (self->child, bounds);
+
+  for (i = 0; i < self->n_shadows; i++)
+    {
+      float clip_radius = gsk_cairo_blur_compute_pixels (self->shadows[i].radius);
+      top = MAX (top, clip_radius - self->shadows[i].dy);
+      right = MAX (right, clip_radius + self->shadows[i].dx);
+      bottom = MAX (bottom, clip_radius + self->shadows[i].dy);
+      left = MAX (left, clip_radius - self->shadows[i].dx);
+    }
+
+  bounds->origin.x -= left;
+  bounds->origin.y -= top;
+  bounds->size.width += left + right;
+  bounds->size.height += top + bottom;
+}
+
+static const GskRenderNodeClass GSK_SHADOW_NODE_CLASS = {
+  GSK_SHADOW_NODE,
+  sizeof (GskShadowNode),
+  "GskShadowNode",
+  gsk_shadow_node_finalize,
+  gsk_shadow_node_make_immutable,
+  gsk_shadow_node_draw,
+  gsk_shadow_node_get_bounds
+};
+
+/**
+ * gsk_shadow_node_new:
+ * @child: The node to draw
+ * @shadows: (array length=n_shadows): The shadows to apply
+ * @n_shadows: number of entries in the @shadows array
+ *
+ * Creates a #GskRenderNode that will draw a @child with the given
+ * @shadows below it.
+ *
+ * Returns: A new #GskRenderNode
+ *
+ * Since: 3.90
+ */
+GskRenderNode *
+gsk_shadow_node_new (GskRenderNode         *child,
+                     const GskShadow       *shadows,
+                     gsize                  n_shadows)
+{
+  GskShadowNode *self;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
+  g_return_val_if_fail (shadows != NULL, NULL);
+  g_return_val_if_fail (n_shadows > 0, NULL);
+
+  self = (GskShadowNode *) gsk_render_node_new (&GSK_SHADOW_NODE_CLASS);
+
+  self->child = gsk_render_node_ref (child);
+  self->shadows = g_memdup (shadows, n_shadows * sizeof (GskShadow));
+  self->n_shadows = n_shadows;
+
+  return &self->render_node;
+}
+
+GskRenderNode *
+gsk_shadow_node_get_child (GskRenderNode *node)
+{
+  GskShadowNode *self = (GskShadowNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_SHADOW_NODE), NULL);
+
+  return self->child;
+}
+
+const GskShadow *
+gsk_shadow_node_peek_shadow (GskRenderNode *node,
+                             gsize          i)
+{
+  GskShadowNode *self = (GskShadowNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_SHADOW_NODE), NULL);
+  g_return_val_if_fail (i < self->n_shadows, NULL);
+
+  return &self->shadows[i];
+}
+
+gsize
+gsk_shadow_node_get_n_shadows (GskRenderNode *node)
+{
+  GskShadowNode *self = (GskShadowNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_SHADOW_NODE), 0);
+
+  return self->n_shadows;
+}
+
 /*** GSK_BLEND_NODE ***/
 
 typedef struct _GskBlendNode GskBlendNode;
index 24e87e8880f3e48de5f58f328b6a3124f74cf9b8..d56c85ce3be94abb9616b6a13d95fd4955fde569 100644 (file)
@@ -62,6 +62,10 @@ const graphene_rect_t * gsk_clip_node_peek_clip (GskRenderNode *node);
 
 const GskRoundedRect * gsk_rounded_clip_node_peek_clip (GskRenderNode *node);
 
+GskRenderNode * gsk_shadow_node_get_child (GskRenderNode *node);
+const GskShadow * gsk_shadow_node_peek_shadow (GskRenderNode *node, gsize i);
+gsize gsk_shadow_node_get_n_shadows (GskRenderNode *node);
+
 void gsk_transform_node_get_transform (GskRenderNode *node, graphene_matrix_t *transform);
 
 GskRenderNode * gsk_blend_node_get_bottom_child (GskRenderNode *node);
index c7037a7a3e1817c919e698b3cc23a6b497050a3f..40fb07af6cf79454d51afcfc65699cbba159ae5c 100644 (file)
@@ -268,6 +268,25 @@ _gtk_css_shadows_value_is_none (const GtkCssValue *shadows)
   return shadows->len == 0;
 }
 
+GskShadow *
+gtk_css_shadows_value_get_shadows (const GtkCssValue *shadows,
+                                   gsize             *n_shadows)
+{
+  GskShadow *result;
+  guint i;
+
+  result = g_new (GskShadow, shadows->len);
+
+  for (i = 0; i < shadows->len; i++)
+    {
+      gtk_css_shadow_value_get_shadow (shadows->values[i], &result[i]);
+    }
+
+  *n_shadows = shadows->len;
+
+  return result;
+}
+
 void
 _gtk_css_shadows_value_paint_layout (const GtkCssValue *shadows,
                                      cairo_t           *cr,
index a0e6b66d7c145a13a15f5ee10a64b7ef1e3dad96..039c8f0cb786dc56657a3737db11501e3f9ad4b7 100644 (file)
@@ -36,6 +36,9 @@ GtkCssValue *   _gtk_css_shadows_value_parse          (GtkCssParser
 
 gboolean        _gtk_css_shadows_value_is_none        (const GtkCssValue        *shadows);
 
+GskShadow *     gtk_css_shadows_value_get_shadows     (const GtkCssValue        *shadows,
+                                                       gsize                    *n_shadows);
+
 void            _gtk_css_shadows_value_paint_layout   (const GtkCssValue        *shadows,
                                                        cairo_t                  *cr,
                                                        PangoLayout              *layout);
index f68a39e66c06ad501cfcab0b6a03286ac76c400d..c0cccd78355eac94f70a799336e03c59e4cb9af8 100644 (file)
@@ -625,6 +625,17 @@ gtk_css_shadow_value_get_extents (const GtkCssValue *shadow,
   border->left = MAX (0, ceil (clip_radius + spread - hoffset));
 }
 
+void
+gtk_css_shadow_value_get_shadow (const GtkCssValue *value,
+                                 GskShadow         *shadow)
+{
+  shadow->color = *_gtk_css_rgba_value_get_rgba (value->color);
+  shadow->dx = _gtk_css_number_value_get (value->hoffset, 0);
+  shadow->dy = _gtk_css_number_value_get (value->voffset, 0);
+  shadow->spread = _gtk_css_number_value_get (value->spread, 0);
+  shadow->radius = _gtk_css_number_value_get (value->radius, 0);
+}
+
 static gboolean
 has_empty_clip (cairo_t *cr)
 {
index 4eb6b7967fb263f490820af6526f9d2c456ae7c1..2c139c86e8f8c26322568d858ba5cb0d40f17f5c 100644 (file)
@@ -39,6 +39,8 @@ gboolean        _gtk_css_shadow_value_get_inset       (const GtkCssValue
 
 void            gtk_css_shadow_value_get_extents      (const GtkCssValue        *shadow,
                                                        GtkBorder                *border);
+void            gtk_css_shadow_value_get_shadow       (const GtkCssValue        *value,
+                                                       GskShadow                *shadow);
 
 void            _gtk_css_shadow_value_paint_layout    (const GtkCssValue        *shadow,
                                                        cairo_t                  *cr,
index 3af2613b76dc57a097f847ecb2ce5eff3fcf3be4..15f8397d3cee0dc684aed60ffe0df04d6536ddd7 100644 (file)
@@ -95,10 +95,11 @@ gtk_css_style_snapshot_icon (GtkCssStyle            *style,
                              double                  height,
                              GtkCssImageBuiltinType  builtin_type)
 {
-  const GtkCssValue *shadows, *transform;
-  static gboolean shadow_warning;
+  const GtkCssValue *shadows_value, *transform;
   graphene_matrix_t transform_matrix;
   GtkCssImage *image;
+  GskShadow *shadows;
+  gsize n_shadows;
 
   g_return_if_fail (GTK_IS_CSS_STYLE (style));
   g_return_if_fail (snapshot != NULL);
@@ -107,17 +108,15 @@ gtk_css_style_snapshot_icon (GtkCssStyle            *style,
   if (image == NULL)
     return;
 
-  shadows = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW);
+  shadows_value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW);
   transform = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_TRANSFORM);
 
   if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix))
     return;
 
-  if (!_gtk_css_shadows_value_is_none (shadows) && !shadow_warning)
-    {
-      g_warning ("Painting shadows not implemented for textures yet.");
-      shadow_warning = TRUE;
-    }
+  shadows = gtk_css_shadows_value_get_shadows (shadows_value, &n_shadows);
+  if (shadows)
+    gtk_snapshot_push_shadow (snapshot, shadows, n_shadows, "IconShadow<%zu>", n_shadows);
 
   if (graphene_matrix_is_identity (&transform_matrix))
     {
@@ -139,6 +138,12 @@ gtk_css_style_snapshot_icon (GtkCssStyle            *style,
 
       gtk_snapshot_pop_and_append (snapshot);
     }
+
+  if (shadows)
+    {
+      gtk_snapshot_pop_and_append (snapshot);
+      g_free (shadows);
+    }
 }
 
 static gboolean
@@ -261,18 +266,19 @@ gtk_css_style_snapshot_icon_texture (GtkCssStyle *style,
                                      GskTexture  *texture,
                                      double       texture_scale)
 {
-  const GtkCssValue *shadows, *transform;
+  const GtkCssValue *shadows_value, *transform;
   graphene_matrix_t transform_matrix;
   graphene_rect_t bounds;
   double width, height;
-  static gboolean shadow_warning;
+  GskShadow *shadows;
+  gsize n_shadows;
 
   g_return_if_fail (GTK_IS_CSS_STYLE (style));
   g_return_if_fail (snapshot != NULL);
   g_return_if_fail (GSK_IS_TEXTURE (texture));
   g_return_if_fail (texture_scale > 0);
 
-  shadows = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW);
+  shadows_value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW);
   transform = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_TRANSFORM);
   width = gsk_texture_get_width (texture) / texture_scale;
   height = gsk_texture_get_height (texture) / texture_scale;
@@ -280,11 +286,9 @@ gtk_css_style_snapshot_icon_texture (GtkCssStyle *style,
   if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix))
     return;
 
-  if (!_gtk_css_shadows_value_is_none (shadows) && !shadow_warning)
-    {
-      g_warning ("Painting shadows not implemented for textures yet.");
-      shadow_warning = TRUE;
-    }
+  shadows = gtk_css_shadows_value_get_shadows (shadows_value, &n_shadows);
+  if (shadows)
+    gtk_snapshot_push_shadow (snapshot, shadows, n_shadows, "IconShadow<%zu>", n_shadows);
 
   if (graphene_matrix_is_identity (&transform_matrix))
     {
@@ -311,4 +315,10 @@ gtk_css_style_snapshot_icon_texture (GtkCssStyle *style,
 
       gtk_snapshot_pop_and_append (snapshot);
     }
+
+  if (shadows)
+    {
+      gtk_snapshot_pop_and_append (snapshot);
+      g_free (shadows);
+    }
 }
index e977e4af9f26bf567766d9fb7edcaadc0c42ac8e..06895d6ad335e2c5916ad1acd6e63dfa34ec70fe 100644 (file)
@@ -472,6 +472,67 @@ gtk_snapshot_push_rounded_clip (GtkSnapshot          *snapshot,
   cairo_region_destroy (clip);
 }
 
+typedef struct {
+  gsize n_shadows;
+  GskShadow shadows[0];
+} Shadow;
+
+static GskRenderNode *
+gtk_snapshot_collect_shadow (GskRenderNode **nodes,
+                             guint           n_nodes,
+                             const char     *name,
+                             gpointer        data)
+{
+  Shadow *shadow = data;
+  GskRenderNode *node, *shadow_node;
+
+  node = gtk_snapshot_collect_default (nodes, n_nodes, name, NULL);
+  if (node == NULL)
+    return NULL;
+
+  shadow_node = gsk_shadow_node_new (node, shadow->shadows, shadow->n_shadows);
+  gsk_render_node_set_name (shadow_node, name);
+
+  gsk_render_node_unref (node);
+  g_free (shadow);
+
+  return shadow_node;
+}
+
+void
+gtk_snapshot_push_shadow (GtkSnapshot            *snapshot,
+                          const GskShadow        *shadow,
+                          gsize                   n_shadows,
+                          const char             *name,
+                          ...)
+{
+  Shadow *real_shadow;
+  char *str;
+
+  real_shadow = g_malloc (sizeof (GskShadow) * n_shadows + sizeof (GskShadow));
+  real_shadow->n_shadows = n_shadows;
+  memcpy (real_shadow->shadows, shadow, sizeof (GskShadow) * n_shadows);
+
+  if (name)
+    {
+      va_list args;
+
+      va_start (args, name);
+      str = g_strdup_vprintf (name, args);
+      va_end (args);
+    }
+  else
+    str = NULL;
+  
+  snapshot->state = gtk_snapshot_state_new (snapshot->state,
+                                            str,
+                                            snapshot->state->clip_region,
+                                            snapshot->state->translate_x,
+                                            snapshot->state->translate_y,
+                                            gtk_snapshot_collect_shadow,
+                                            real_shadow);
+}
+
 /**
  * gtk_snapshot_pop:
  * @snapshot: a #GtkSnapshot
index c5c2d20b3da0c191c16b1a0f734b07fe8bc6cf5a..22a12a352747088bc025eb5d72a44c1c099973cc 100644 (file)
@@ -62,6 +62,12 @@ void            gtk_snapshot_push_rounded_clip          (GtkSnapshot
                                                          const char             *name,
                                                          ...) G_GNUC_PRINTF (3, 4);
 GDK_AVAILABLE_IN_3_90
+void            gtk_snapshot_push_shadow                (GtkSnapshot            *snapshot,
+                                                         const GskShadow        *shadow,
+                                                         gsize                   n_shadows,
+                                                         const char             *name,
+                                                         ...) G_GNUC_PRINTF (4, 5);
+GDK_AVAILABLE_IN_3_90
 GskRenderNode * gtk_snapshot_pop                        (GtkSnapshot            *snapshot) G_GNUC_WARN_UNUSED_RESULT;
 GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_pop_and_append             (GtkSnapshot            *snapshot);
index 96b0d944e9b556dec50396a84bf279be84779e39..6064f9c43111439fd9d769a0c01a58ce91b82817 100644 (file)
@@ -547,6 +547,10 @@ append_node (GtkTreeModelRenderNode *nodemodel,
       append_node (nodemodel, gsk_rounded_clip_node_get_child (node), priv->nodes->len - 1);
       break;
 
+    case GSK_SHADOW_NODE:
+      append_node (nodemodel, gsk_shadow_node_get_child (node), priv->nodes->len - 1);
+      break;
+
     case GSK_BLEND_NODE:
       {
         int elt_index = priv->nodes->len - 1;
index b87e043b3b91703c141734c8d07da082f70cfc55..d1b41175562da7a5d71328bdbdbd60023efdb7c4 100644 (file)
@@ -159,6 +159,8 @@ node_type_name (GskRenderNodeType type)
       return "Clip";
     case GSK_ROUNDED_CLIP_NODE:
       return "Rounded Clip";
+    case GSK_SHADOW_NODE:
+      return "Shadow";
     case GSK_BLEND_NODE:
       return "Blend";
     case GSK_CROSS_FADE_NODE: